package com.xiaoma.socket

import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.usage.NetworkStats
import android.app.usage.NetworkStats.Bucket
import android.app.usage.NetworkStatsManager
import android.content.ComponentName
import android.content.Intent
import android.net.ConnectivityManager
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.content.getSystemService
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleService
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.runInterruptible
import java.net.ServerSocket

class ForegroundService : LifecycleService() {
    companion object {
        private val TAG = "${ForegroundService::class.simpleName}Tag"

        private const val CHANNEL_ID = "FG_SERVICE_CHANNEL_ID"
        private const val CHANNEL_NAME = "FG_SERVICE_CHANNEL_NAME"
        private const val CHANNEL_IMPORTANCE = NotificationManager.IMPORTANCE_DEFAULT

        private const val SERVICE_ID = 1

        fun start(app: Application) {
            val intent = Intent().apply {
                component = ComponentName(
                    app.packageName,
                    ForegroundService::class.java.name
                )
            }
            app.startService(intent)
        }

        private val _enableState = MutableStateFlow(false)
        val enableState: StateFlow<Boolean> = _enableState
    }

    override fun onCreate() {
        super.onCreate()
        Log.i(TAG, "onCreate")
        getSystemService<NotificationManager>()?.let { manager ->
            val channel = NotificationChannel(
                CHANNEL_ID,
                CHANNEL_NAME,
                CHANNEL_IMPORTANCE
            )
            channel.description = "Socket前台服务"
            manager.createNotificationChannel(channel)
        }

        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                combine(
                    PermissionManager.granted,
                    NetworkStateWatcher.ipAddresses,
                    ::Pair
                ).collect { (granted, ip) ->
                    when {
                        !granted -> Unit

                        ip.isEmpty() -> {
                            Log.i(TAG, "stopForeground")
                            stopForeground(STOP_FOREGROUND_REMOVE)
                            _enableState.update { false }
                        }

                        else -> {
                            val intent = PendingIntent.getActivity(
                                application,
                                0,
                                Intent(application, MainActivity::class.java),
                                PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE,
                            )

                            val notification = NotificationCompat.Builder(
                                this@ForegroundService,
                                CHANNEL_ID
                            ).setContentIntent(intent)
                                .build()

                            Log.i(TAG, "startForeground")
                            startForeground(SERVICE_ID, notification)
                            _enableState.update { true }
                        }
                    }
                }
            }
        }
    }

    init {
        lifecycleScope.launch(Dispatchers.IO) {
            combine(
                enableState,
                PermissionManager.granted,
                PortManager.port,
                ::Triple
            ).collectLatest { (enable, granted, port) ->
                Log.d(TAG, "enable: $enable, granted: $granted")
                when (enable && granted) {
                    false -> Unit
                    true -> runInterruptible {
                        val server = ServerSocket(port)
                        while (!Thread.currentThread().isInterrupted) {
                            startServerSocket(server)
                        }
                    }
                }
            }
        }
    }

    private fun startServerSocket(server: ServerSocket) {
        Log.i(TAG, "accept")
        val socket = server.accept()
        if (Thread.currentThread().isInterrupted) throw InterruptedException()
        Log.i(TAG, "accepted")

        socket.getInputStream().use { ips ->
            ips.bufferedReader(Charsets.UTF_8).use { br ->
                val uid = br.readLine()

                Log.i(TAG, "uid: $uid")
                val result = handleUid(uid)
                Log.i(TAG, "handleUid result: $result")

                socket.getOutputStream().use { ops ->
                    ops.write(result.toByteArray(Charsets.UTF_8))
                }
            }
        }
    }

    private fun handleUid(uidString: String): String = runCatching {
        // 将uid转为为int值
        val uid = uidString.toInt()
        // 获取系统服务
        val manager = getSystemService<NetworkStatsManager>()
            ?: return "NetworkStatsManager is null"

        fun load(stats: NetworkStats) = run {
            // 创建一个桶来填充数据
            val bucket = Bucket()
            sequence {
                // 判断是否有剩余数据
                while (stats.hasNextBucket()) {
                    // 有剩余数据,填充到桶中
                    stats.getNextBucket(bucket)
                    yield(bucket.rxBytes to bucket.txBytes)
                }
            }.reduceOrNull() { (rxTotal, txTotal), (rx, tx) ->
                // 整合所有数据
                (rxTotal + rx) to (txTotal + tx)
            } ?: (0 to 0)
        }

        val mobileStats = manager.queryDetailsForUid(
            ConnectivityManager.TYPE_MOBILE, // 流量类型
            "",                 // 弃用参数, 传递空字符串
            0,                    // 起始时间
            System.currentTimeMillis(),    // 结束时间
            uid                            // 包的uid
        )
        val (mobileRx, mobileTx) = load(mobileStats)
        Log.d(TAG, "mobile: rx: $mobileRx, tx: $mobileTx")

        val wifiStats = manager.queryDetailsForUid(
            ConnectivityManager.TYPE_WIFI, // 流量类型
            "",                 // 弃用参数, 传递空字符串
            0,                    // 起始时间
            System.currentTimeMillis(),    // 结束时间
            uid                            // 包的uid
        )
        val (wifiRx, wifiTx) = load(wifiStats)
        Log.d(TAG, "wifi: rx: $wifiRx, tx: $wifiTx")

        // 返回rx数据与tx数据
        "mobile:$mobileRx,$mobileTx|wifi:$wifiRx,$wifiTx"
    }.getOrElse { e ->
        // 出错了,返回出错信息
        """handle failure
            | ${e.cause}
            | ${e.stackTraceToString().lines().joinToString(System.lineSeparator()) { "|  $it" }}
        """.trimMargin()
    }
}